/*
 * $Id: SecurityContextHelper.java 42 2013-04-17 15:33:59Z gabakyan $
 * $Author: gabakyan $
 * $Revision: 42 $
 * $Date: 2013-04-17 15:33:59 +0000 (Wed, 17 Apr 2013) $
 *
 * Copyright (c) 2013 Supply Chain Intelligence (SCI), Inc.
 * http://www.scintelligence.com/, Email: info@scintelligence.com
 * All rights reserved.
 *
 * This file is part of Logistics Map.
 *
 * Logistics Map is free software: you can redistribute it and/or modify
 * it under the terms of the GNU General Public License as published by
 * the Free Software Foundation, version 3 of the License.
 *
 * Logistics Map is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 * GNU General Public License for more details.
 *
 * You should have received a copy of the GNU General Public License
 * along with Logistics Map.  If not, see <http://www.gnu.org/licenses/>.
 */

package com.sci.logisticsmap.web.security.support;

import com.sci.logisticsmap.service.model.SessionUserDTModel;
import com.sci.logisticsmap.web.security.UserDetailsImpl;
import org.springframework.security.core.Authentication;
import org.springframework.security.core.context.SecurityContext;
import org.springframework.security.core.context.SecurityContextHolder;
import org.springframework.security.core.userdetails.UserDetails;

import javax.servlet.http.HttpSession;

/**
 * The utility class which provides helper methods for accessing the security context.
 *
 * @author gabakyan@gmail.com (Last modified by $Author: gabakyan $)
 * @version $Revision: 42 $
 */
public final class SecurityContextHelper {
    /**
     * The string representation of the anonymous user principal.
     */
    private static final String PRINCIPAL_STRING_ANONYMOUS_USER = "anonymousUser";
    /**
     * The spring security context session key.
     */
    private static final String SPRING_SECURITY_CONTEXT_SESSION_KEY = "SPRING_SECURITY_CONTEXT";

    /**
     * The private constructor.
     */
    private SecurityContextHelper() {
    }

    /**
     * Returns the authenticated user details.
     *
     * @return The authenticated user details.
     */
    public static UserDetailsImpl getAuthenticatedUser() {
        return getAuthenticatedUser(SecurityContextHolder.getContext());
    }

    /**
     * Returns the authenticated user details.
     *
     * @param session The http session.
     *
     * @return The authenticated user details.
     */
    public static UserDetailsImpl getAuthenticatedUser(HttpSession session) {
        SecurityContext securityContext;
        if ((securityContext = getSecurityContextFromSession(session)) != null) {
            return getAuthenticatedUser(securityContext);
        }
        return null;
    }

    /**
     * Returns the authenticated user details <code>user</code> attribute.
     *
     * @return The authenticated user details <code>user</code> attribute.
     */
    public static SessionUserDTModel getAuthenticatedUserDTModel() {
        return getAuthenticatedUserDTModel(SecurityContextHolder.getContext());
    }

    /**
     * Returns the authenticated user details <code>user</code> attribute.
     *
     * @param session The http session.
     *
     * @return The authenticated user details <code>user</code> attribute.
     */
    public static SessionUserDTModel getAuthenticatedUserDTModel(HttpSession session) {
        SecurityContext securityContext;
        if ((securityContext = getSecurityContextFromSession(session)) != null) {
            return getAuthenticatedUserDTModel(securityContext);
        }
        return null;
    }

    /**
     * Checks authentication of the user associated with the current session.
     *
     * @return <code>true</code> if the user associated with the current session is authenticated, otherwise
     * <code>false</code>.
     *
     * @see #isAuthenticatedUser(org.springframework.security.core.context.SecurityContext)
     */
    public static boolean isAuthenticatedUser() {
        return isAuthenticatedUser(SecurityContextHolder.getContext());
    }

    /**
     * Checks authentication of the user associated with the current session.
     *
     * @param session The http session.
     *
     * @return <code>true</code> if the user associated with the current session is authenticated, otherwise
     * <code>false</code>.
     *
     * @see #isAuthenticatedUser(org.springframework.security.core.context.SecurityContext)
     */
    public static boolean isAuthenticatedUser(HttpSession session) {
        SecurityContext securityContext;
        if ((securityContext = getSecurityContextFromSession(session)) != null) {
            return isAuthenticatedUser(securityContext);
        }
        return false;
    }

    /**
     * Checks authentication of the user associated with the current session.
     *
     * @return <code>true</code> if the user associated with the current session is not authenticated, otherwise
     * <code>false</code>.
     *
     * @see #isAuthenticatedUser()
     */
    public static boolean isAnonymousUser() {
        return !isAuthenticatedUser();
    }

    /**
     * Checks authentication of the user associated with the current session.
     *
     * @param session The http session.
     *
     * @return <code>true</code> if the user associated with the current session is not authenticated, otherwise
     * <code>false</code>.
     *
     * @see #isAuthenticatedUser(javax.servlet.http.HttpSession)
     */
    public static boolean isAnonymousUser(HttpSession session) {
        return !isAuthenticatedUser(session);
    }

    /**
     * Returns the authenticated user.
     *
     * @param securityContext The security context.
     *
     * @return The authenticated user.
     */
    private static UserDetailsImpl getAuthenticatedUser(SecurityContext securityContext) {
        Authentication authentication = securityContext.getAuthentication();
        if (authentication != null) {
            Object principal = authentication.getPrincipal();
            //if (principal != null && principal instanceof String) {// anonymousUser
            if (principal != null && principal instanceof UserDetails) {
                return (UserDetailsImpl) principal;
            }
        }
        return null;
    }

    /**
     * Returns the authenticated user details <code>user</code> attribute.
     *
     * @param securityContext The security context.
     *
     * @return The authenticated user details <code>user</code> attribute.
     */
    private static SessionUserDTModel getAuthenticatedUserDTModel(SecurityContext securityContext) {
        UserDetailsImpl userDetails = getAuthenticatedUser(securityContext);
        if (userDetails != null) {
            return userDetails.getUser();
        }
        return null;
    }

//    /**
//     * Updates the authenticated user details <code>user</code> attribute.
//     *
//     * @param user The user.
//     */
//    public static void setAuthenticatedUserDTModel(SessionUserDTModel user) {
//        UserDetailsImpl userDetails = getAuthenticatedUser();
//        if (userDetails != null) {
//            userDetails.setUser(user);
//        }
//    }

    /**
     * Checks authentication of the current user.
     *
     * @param securityContext The security context.
     *
     * @return <code>true</code> if the current user is authenticated, otherwise
     * <code>false</code>.
     */
    private static boolean isAuthenticatedUser(SecurityContext securityContext) {
        Authentication authentication = securityContext.getAuthentication();
        if (authentication != null) {
            Object principal = authentication.getPrincipal();
            return !(principal == null || (principal instanceof String && principal.equals(PRINCIPAL_STRING_ANONYMOUS_USER)));
        }
        return false;
    }

    /**
     * Checks authentication of the current user.
     *
     * @param securityContext The security context.
     *
     * @return <code>true</code> if the current user is not authenticated, otherwise
     * <code>false</code>.
     *
     * @see #isAuthenticatedUser(org.springframework.security.core.context.SecurityContext)
     */
    private static boolean isAnonymousUser(SecurityContext securityContext) {
        return !isAuthenticatedUser(securityContext);
    }

    /**
     * Returns the security context associated with the current session.
     *
     * @param session The http session.
     *
     * @return The security context associated with the current session.
     */
    private static SecurityContext getSecurityContextFromSession(HttpSession session) {
        return (SecurityContext) session.getAttribute(SPRING_SECURITY_CONTEXT_SESSION_KEY);
    }
}
